#pragma once

#include <string>
#include <vector>
#include <sstream>
#include <xtd/exception>

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

typedef std::vector<char> reg_blob;

/**
 * Gives simple access to Windows registry subtree
 */
class regprofile {
public:
	typedef std::string string;
	exception_struct(error);
	/// Thrown when given path does not exist, and creation is failed or not requested
	exception_struct1(not_found, error);
	/// Thrown when process attempts go beyond its commission
	exception_struct1(access_denied, error);
	/// Thrown when parameter value does not match requested type
	exception_struct1(parse_error, error);
	/// Thrown when the type of read value is incompatible with requested type
	exception_struct1(incompatible_type, parse_error);
public:
	regprofile();
	/// Creates profile from a subtree specified by the pair: key and relative path; 
	/// if create, all not existing subkeys are created;
	/// if nothrow, not_found and access_denied are never thrown
	regprofile(HKEY hkey, string const & path = string(), bool create = true, bool nothrow = false);
	void open(HKEY hkey, string const & path = string(), bool create = true, bool nothrow = false);
	void close();
	bool is_open() const;
	~regprofile();
public:
	/** Note about path. 
	 * If path ends with backslash, then it denotes subkey or its default value (like directory in file system).
	 * If path does not end with backslash, then it points on a value (file in filesystem).
	 */
	/// If error occurs, an exception is thrown
	template <typename T> 
	void get0(string const & path, T & value) const;
	template <typename T> 
	T get(string const & path) const;
	/// If error occurs or the profile was not opened, default value is returned
	template <typename T> 
	void get(string const & path, T & value, const T & def) const;
	template <typename T> 
	T get(string const & path, const T & def) const;
	/// Returns true if given parameter exists and access to it is not denied; no exception is ever thrown
	bool query(string const & path) const;
	/// Returns true if given parameter exists and access to it is not denied; 
	/// if parse error occurs, an exception is thrown
	template <typename T> 
	bool query(string const & path, T & value) const;
	/// Returns true if given parameter exists and access to it is not denied; 
	/// if parse error occurs or the profile was not opened, default value is returned
	template <typename T> 
	bool query(string const & path, T & value, const T & def) const;
public:
	/// If error occurs, an exception is thrown
	template <typename T> 
	void set(string const & path, T const & value);
public:
	/// If error occurs (including absence of the value), an exception is thrown
	void remove(string const & path);
	/// Returns true if given path existed and was deleted;
	/// if access is denied, an exception is thrown
	bool erase(string const & path);
private:
	static void classify_error(LONG r, string message);
	static void split_path(string const & path, string & key_name, string & value_name);
	void get_regvalue_meta(string const & value_name, DWORD & cbData, DWORD & type) const;
	void get_regvalue(string const & value_name, DWORD & cbData, void * data) const;
	//following functions should workaround INTERNAL COMPILER ERROR in vc7.1 due to methods specialization
	void get_string(string const & path, string & value) const;
	void get_blob(string const & path, reg_blob & value) const;
	void get_llint(string const & path, long long & value) const;
	void get_double(string const & path, double & value) const;
	void set_string(string const & path, string const & value);
	void set_blob(string const & path, reg_blob const & value);
	void set_int(string const & path, int value);
	void set_llint(string const & path, long long const & value);
private:
	HKEY hbase;
};

// template implementation
#include "regprofile_impl.h"
